package com.zyl.lock;

import java.util.concurrent.TimeUnit;

/**
 * @author zhaoyl
 * @date 2024/5/20 22:25
 * @description 说明
 * 概念
 * (1) 死锁：各进程互相等待对方手里的资源，导致各进程都阻塞，无法向前推进
 * (2) 饥饿：长期得不到想要的资源，某进程无法向前推进
 * (3) 死循环：某进程执行过程中一直跳不出某个循环
 *
 * 死锁产生的必要条件
 * 产生死锁必须同时满足以下四个条件，若有一个不满足，死锁就不会发生
 * (1) 互斥条件：对互斥使用的资源的争夺才会导致死锁
 * (2) 不剥夺条件：进程获得的资源在未使用完之前，不能由其他进程强行夺走，只能主动释放
 * (3) 请求和保持条件：进程已经保持了至少一个资源，但又提出了新的资源请求，而该资源又 被其他进程占有，此时请求进程被阻塞，但又对自己已有的资源保持不放
 * (4) 循环等待条件：存在一种进程资源的循环等待链，链中的每一个进程已获得的资源同时被 下一个进程所请求
 *
 * 死锁的处理策略
 * (1) 预防死锁：破坏死锁产生的四个必要条件中的一个或几个
 * (2) 避免死锁：用某种方法防止系统进入不安全状态，从而避免死锁
 * (3) 死锁的检测和解除：允许死锁的发生，操作系统检测出死锁后，会采取措施解除死锁
 *定位死锁信息：1查看日志，2查看堆信息
 * 使用jps 命令查看堆死锁 ；jps -1 定位进程号
 * > jps -1
 * 使用jstack 查询进程信息
 * > jstack 11140
 * 分段锁
 * 分段锁其实是一种锁的设计，并不是具体的一种锁，对于ConcurrentHashMap而言，其并发的实现就是通过分段锁的形式来实现高效的并发操作。
 * 我们以ConcurrentHashMap来说一下分段锁的含义以及设计思想，ConcurrentHashMap中的分段锁称为Segment，它即类似于HashMap（JDK7与JDK8中HashMap的实现）的结构，即内部拥有一个Entry数组，数组中的每个元素又是一个链表；同时又是一个ReentrantLock（Segment继承了ReentrantLock)。
 * 当需要put元素的时候，并不是对整个hashmap进行加锁，而是先通过hashcode来知道他要放在那一个分段中，然后对这个分段进行加锁，所以当多线程put的时候，只要不是放在一个分段中，就实现了真正的并行的插入。
 * 但是，在统计size的时候，可就是获取hashmap全局信息的时候，就需要获取所有的分段锁才能统计。
 * 分段锁的设计目的是细化锁的粒度，当操作不需要更新整个数组的时候，就仅仅针对数组中的一项进行加锁操作。
 *
 * 偏向锁/轻量级锁/重量级锁
 * 这三种锁是指锁的状态，并且是针对Synchronized。在Java 5通过引入锁升级的机制来实现高效Synchronized。这三种锁的状态是通过对象监视器在对象头中的字段来表明的。
 * 偏向锁是指一段同步代码一直被一个线程所访问，那么该线程会自动获取锁。降低获取锁的代价。
 * 轻量级锁是指当锁是偏向锁的时候，被另一个线程所访问，偏向锁就会升级为轻量级锁，其他线程会通过自旋的形式尝试获取锁，不会阻塞，提高性能。
 * 重量级锁是指当锁为轻量级锁的时候，另一个线程虽然是自旋，但自旋不会一直持续下去，当自旋一定次数的时候，还没有获取到锁，就会进入阻塞，该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞，性能降低。
 */
public class DeadlockDemo {

    public static void main(String[] args) {
         String  lockA = "lockA";
         String  lockB = "lockB";

        new Thread(new MyThred(lockA,lockB),"线程T1").start();
        new Thread(new MyThred(lockB,lockA),"线程T2").start();
    }
}
//死锁线程
class  MyThred implements  Runnable{
    private String  lockA;
    private String  lockB;

    public MyThred(String lockA, String lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }

    @Override
    public void run() {
        synchronized (lockA){
            System.out.println(Thread.currentThread().getName()+"lockA:"+lockA+"=>get"+lockB);//A获取B锁
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lockB){
                System.out.println(Thread.currentThread().getName()+"lockB:"+lockB+"=>get"+lockA);//B获取A锁
            }
        }
    }
}